perm filename SUPSER.MID[NET,MRC]6 blob sn#357047 filedate 1978-05-26 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00016 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00003 00002	TITLE SUPSER
C00004 00003	ITS TTY definitions
C00009 00004	 More ITS TTY definitions
C00013 00005	IMPSET LINCHR XONOFF DTMSET GAGOFF SETVSZ MODSET CNSBLK TCTYP TTYOPT TCMXV TCMXH TTYROL SMARTS ISPEED OSPEED TERMID TERSTR HPOS VPOS SCRMST GETCXP GETCYP INDLMP ROLLP LFFLSP QUOTEP 128CHP OVRPRP PTINTP NTINTP PRESCP SDCMDP EATERP NODETP BKYBTS FLSCNT TERMBP TTYLIN IDLTIM PTIBUF PDL
C00017 00006	INTSER CLKSER CLKSR1
C00019 00007	SUPSER CPYHST 1DIGTP NOTTIP
C00022 00008	GETSIZ GETCNS CHKTRM NOTSAI
C00025 00009	GETPTY MAINL MAINL0
C00027 00010	NTISER
C00030 00011	PTYSN0 FNYQOT PTYSN1 PTYSN2 PTYSND
C00033 00012	PTISER PTISR1 CHKCYP CHKDMC DMSND DMSND0 MRKNBL ISPCH NOTPCH
C00036 00013	SCLEAR CANCEL CLEOL SETCPS INSLIN IDCMND SPACE FORSPC
C00039 00014	DMCTAB
C00043 00015	 More DM command frobs
C00046 00016	GETSMD BITTAB SNDMSG MSGLUP INTDIE SUICID DIEDIE ...LIT
C00049 ENDMK
C⊗;
TITLE SUPSER
SUBTTL Definitions

; Mark Crispin, SU-AI, May 1978

; Assembly switches

IFNDEF SVRSKT,SVRSKT==137		; default listen socket
IFNDEF LOKTMO,LOKTMO==5			; # of 15-second frobs of lock timeout
IFNDEF PDLLEN,PDLLEN==50		; stack length
IFNDEF VSZMAX,VSZMAX==50.		; maximum TCMXV

; AC definitions.  0→3 are used by NETWRK

X=4 ? Y=5 ? Z=6 ? A=7 ? B=10 ? C=11 ? D==12 ? P=17

; SAIL system bit definitions

INTPTO==001000,,			; PTY interrupt
INTCLK==000200,,			; clock interrupt
FCS==   000020,,			; full character set mode
XON==   000002,,			; paper tape mode
TLKRNG==000001,,			; TALKing
SUBTTL ITS TTY definitions

;  These definitions are the various bits, words, etc. for the ITS terminal
; service system calls and are here for convenience and clarity.  This is
; abridged from [MIT-AI] SYSTEM;BITS >, the monitor bits definition file.

; TTYOPT variable (terminal capabilities)

%TOALT==200000,,			; 1 → standardise altmodes
%TOCLC==100000,,			; 1 → convert cases on input
%TOERS==040000,,			; 1 → this terminal can erase
%TOHDX==020000,,			; 1 → half duplex
%TOMVB==010000,,			; 1 → can backspace
%TOSAI==004000,,			; 1 → has SAIL graphics
%TOSA1==002000,,			; 1 → init %TSSAI in new jobs (use graphics)
%TOOVR==001000,,			; 1 → can overprint
%TOMVU==000400,,			; 1 → can line starve (ie a display)
%TOMOR==000200,,			; 1 → do **More** processing (init %TSMOR)
%TOROL==000100,,			; 1 → scroll (init %TSROL for new jobs)
%TORAW==000040,,			; 1 → no cursor motion optimization
%TOLWR==000020,,			; 1 → lower case keyboard
%TOFCI==000010,,			; 1 → has bucky bit keyboard
%TOIML==000004,,			; 1 → acts like a grIMLAC (funny ↑PF, ↑PB)
%TOLID==000002,,			; 1 → can insert/delete lines
%TOCID==000001,,			; 1 → can insert/delete characters
%TPPLF==700000				; LF padding
%TPPCR==070000				; CR padding
%TPPTB==007000				; TAB padding (0 → no tabs, 1 → tabs)
%TPPRN==000200				; 1 → swap () with [] on input
%TPTEL==000100				; 1 → CR → CRLF for ARPAnet protocol
%TPCBS==000040				; 1 → intelligent terminal protocol (↑\)
%TP11T==000020				; 1 → PDP-11 TV (reflects %TY11T)
%TPORS==000010				; 1 → output reset should do something

; SMARTS variable (terminal smarts)

%TQMCH==700000,,			; machine type
 %TQIM1==300000,,			; PDS1
 %TQIM4==200000,,			; PDS4
 %TQP11==100000,,			; PDP-11
%TQHGT==076000,,			; character height in dots
%TQWID==001700,,			; character width in dots
%TQVIR==000040,,			; virtual coordinates
%TQBNK==000020,,			; blinking
%TQXOR==000010,,			; XOR mode
%TQREC==000004,,			; rectangle command
%TQSET==000002,,			; multiple sets
%TQGRF==000001,,			; understands graphics
%TRGIN==400000				; graphics input
%TRGHC==200000				; hardcopy device

; TCTYP variable (terminal type)

%TNPRT==0				; printing console, glass TTY, etc.
%TNDP==1				; good Datapoint
%TNODP==2				; inferior losing Datapoint
%TNIML==3				; grIMLAC
%TNTEK==4				; Tektronix 4000 series
%TNTV==5				; PDP-11 TV
%TNMEM==6				; Memowreck
%TNSFW==7				; Software
%TNTRM==10				; Terminet
%TNESC==11				; ASCII standard display (VT52, etc.)
%TNDTM==12				; Datamedia 2500
%TNMAX==13				; 1 + largest terminal type

; Components of an input character in 12-bit mode.

%TXASC==0177				; ASCII part
%TXCTL==0200				; control
%TXMTA==0400				; meta
%TXSFT==1000				; shift
%TXSFL==2000				; shift lock
%TXTOP==4000				; top
; More ITS TTY definitions

; Graphics output buffer codes

%GOMVR==001				; move cursor to P
%GOXOR==002				; turn on XOR mode
%GOSET==003				; select set N
%GOMSR==004				; move set origin to P
%GOINV==006				; make current set invisible
%GOBNK==007				; make current set blink
%GOCLR==010				; erase whole screen
%GOPSH==011				; push status information
%GOVIR==012				; use virtual coordinates
%GOHRD==013				; divert output to N
%GOGIN==014				; request input, reply code N
%GOLMT==015				; limit to subrectangle P1 P2
%GOMVA==021				; move cursor to P, abs addr
%GOIOR==022				; turn off XOR mode
%GOMSA==024				; move set origin to P, abs addr
%GOVIS==026				; make current set visible
%GOCLS==030				; erase current set
%GOPHY==032				; use unit coordinates

%GODLR==101				; draw line relative, to P
%GODPR==102				; draw point relative, at P
%GODRR==103				; draw rectangle relative, at P
%GODCH==104				; display STRING
%GODLA==121				; draw line absolute, to P
%GODPA==122				; draw point absolute, at P
%GODRA==123				; draw rectangle absolute, at P

%GOELR==141				; erase line relative, to P
%GOEPR==142				; erase point relative, at P
%GOERR==143				; erase rectangle relative, at P
%GOECH==144				; erase STRING
%GOELA==161				; erase line absolute, to P
%GOEPA==162				; erase point absolute, at P
%GOERA==163				; erase rectangle absolute, at P

; Non-graphics output buffer codes

%TDMOV==200				; move cursor OV OH NV NH
%TDMV1==201				; move cursor; NV NH
%TDEOF==202				; clear to end of screen
%TDEOL==203				; clear to end of line
%TDDLF==204				; delete character after cursor
%TDMTF==205				; motor off
%TDMTN==206				; motor on
%TDCRL==207				; terpri
%TDNOP==210				; no-op
%TDBS==211				; backspace
%TDLF==212				; line feed
%TDRCR==213				; carriage return
%TDORS==214				; output reset
%TDQOT==215				; quote next character (mystery command)
%TDFS==216				; cursor forward
%TDMV0==217				; move cursor NV NH
%TDCLR==220				; clear screen
%TDBEL==221				; feep!
%TDINI==222				; reset reset reset
%TDILP==223				; insert line; count
%TDDLP==224				; delete line; count
%TDICP==225				; insert character; count
%TDDCP==226				; delete character; count
%TDBOW==227				; inverse video
%TDRST==230				; reset inverse video, etc.
%TDMAX==231				; 1 + largest display code
;IMPSET LINCHR XONOFF DTMSET GAGOFF SETVSZ MODSET CNSBLK TCTYP TTYOPT TCMXV TCMXH TTYROL SMARTS ISPEED OSPEED TERMID TERSTR HPOS VPOS SCRMST GETCXP GETCYP INDLMP ROLLP LFFLSP QUOTEP 128CHP OVRPRP PTINTP NTINTP PRESCP SDCMDP EATERP NODETP BKYBTS FLSCNT TERMBP TTYLIN IDLTIM PTIBUF PDL

SUBTTL Data area

; TTYSET command words

TYSBLK==.
IMPSET:	034400,,			; IMP TTY
LINCHR:	001400,,(FCS)			; default line characteristics
XONOFF:	002400,,(XON)			; generate LF after CR
DTMSET:	035400,,			; DM PTY
GAGOFF:	024400,,			; gag off
SETVSZ:	016400,,			; set screen height
MODSET:	014400,,			; set DM mode
NTYSTS==.-TYSBLK

; Terminal characteristics

CNSBLK:	BLOCK 1				; CNSGET info
TCTYP:	%TNSFW				; TCTYP for server
TTYOPT:	%TOERS\%TOMVB\%TOMVU\%TOFCI\%TOLID\%TOCID\%TPCBS ; TTYOPT for server
TCMXV:	24.				; TTY page length
TCMXH:	79.				; TTY width
TTYROL:	0				; TTYROL variable
SMARTS:	0				; SMARTS variable
ISPEED:	0				; input speed
OSPEED:	0				; output speed
CNSBLL==.-CNSBLK

; Terminal location string

TERMID:	'TERMID

CORBEG==.				; start of initialized core storage

TERSTR:	BLOCK 10.			; console location string

; Datamedia translator variables

HPOS:	BLOCK 1				; horizontal position
VPOS:	BLOCK 1				; vertical position
SCRMST:	BLOCK 3*<VSZMAX+1>		; screen character allocation table
GETCXP:	BLOCK 1				; -1 → get cursor X position
GETCYP:	BLOCK 1				; -1 → get cursor Y position
INDLMP:	BLOCK 1				; -1 → in I/D mode
ROLLP:	BLOCK 1				; -1 → in roll mode
LFFLSP:	BLOCK 1				; -1 → flush a line feed
QUOTEP:	BLOCK 1				; -1 → quote next character
128CHP:	BLOCK 1				; -1 → FCS terminal
OVRPRP:	BLOCK 1				; -1 → TV terminal

; Interrupt flags

PTINTP:	BLOCK 1				; -1 → PTI interrupt
NTINTP:	BLOCK 1				; -1 → NTI interrupt

; Protocol flags

PRESCP:	BLOCK 1				; -1 → protocol escape seen
SDCMDP:	BLOCK 1				; -1 → in SUPDUP protocol command
EATERP:	BLOCK 1				; -1 → getting terminal string
NODETP:	BLOCK 1				; -1 → don't detach this guy
BKYBTS:	BLOCK 1				; -1 → incoming bucky bits

; Other storage

FLSCNT:	BLOCK 1				; flush count for NTISER
TERMBP:	BLOCK 1				; terminal byte pointer
TTYLIN:	BLOCK 1				; line number of PTY
IDLTIM:	BLOCK 1				; idle time in 15-second units
PTIBUF:	BLOCK 30.			; PTY input buffer
PDL:	BLOCK PDLLEN			; stack

COREND==.-1				; end of initialized storage
;INTSER CLKSER CLKSR1

SUBTTL Interrupt server

;  Interrupts only set flags which the main program (normally in INTW⊗
; state) looks at.

INTSER:	SKIPN X,JOBCNI			; get interrupt status
	 JRST 4,.-1
	TLNE X,(INTPTO)			; PTY int
	 SETOM PTINTP
	TLNE X,(INTCLK)			; CLK int
	 JRST CLKSER
	TLNE X,(INTINP)			; NTI int
	 SETOM NTINTP
	TLNE X,(INTIMS)			; status change
	 JRST INTDIE
	TLNE X,(INTINR)
	 OUTSTR [ASCIZ/*INR*
/]
	TLNE X,(INTINS)			; IMP INS int
	 OUTSTR [ASCIZ/*INS*
/]
	DISMIS

; Service clock interrupt

CLKSER:	AOSGE IDLTIM			; bump idle time
	 JRST CLKSR1
	UNLOCK				; idle timeout; unlock
	MOVE TTYLIN
	PTGETL
	TLNE 1,(TLKRNG)			; TALKing?
	 JRST CLKSR1			; don't kill him if so!
	TTYJOB
	JUMPN CLKSR1
	SETOM NODETP			; forget about detaching
	JRST INTDIE			; idle and not logged in--bye bye!
CLKSR1:	MOVEI 2				; check connection status
	MTAPE NET,
	TLNN 1,(CLSS\CLSR)		; send side gronked?
	 TLNE 2,(CLSS\CLSR)		; receive side?
	  JRST INTDIE
	DISMIS
;SUPSER CPYHST 1DIGTP NOTTIP

SUBTTL Start of program

SUPSER:	JFCL
	RESET
	MOVE ['SUPSER]
	SETNAM
	SETZM CORBEG
	MOVE [CORBEG,,CORBEG+1]
	BLT COREND
	MOVE P,[PDL(-PDLLEN)]
	MOVEI [DEBREAK ? EXIT]
	MOVEM JOBAPR
	CLKINT 5.*60.*60.		; must die if around too long
	OUTSTR [ASCIZ/SUPSER started
/]

; Listen for a connection on our socket

	SETOM NODETP			; don't try to detach
	MOVEI SVRSKT
	MOVEM LSNSKT
	PUSHJ P,LISTEN

; Set up interrupts

	MOVEI INTSER
	MOVEM JOBAPR			; set up server location
	CLKINT 60.*15.			; start slow ticking clock
	MOVSI (INTPTO\INTCLK\INTINR\INTINS\INTIMS\INTINP)
	INTENB				; turn on interrupts

; Set up terminal id for interested spies

	MOVEI TERMID
	MOVEM JOBVER

; Log this connection

	OUTSTR [ASCIZ/Connected to /]
	PUSHJ P,MAPHST			; map in host table
	MOVE HOST
	PUSHJ P,HSTNUM			; get HDB
	 JFCL				; sorry about errors
	MOVEI Y,(1)			; host name
	HRLI Y,440700
	SKIPA X,[440700,,TERSTR]
CPYHST:	 IDPB Z,X
	ILDB Z,Y
	JUMPN Z,CPYHST
	HLRZ Y,1			; pointer to system name
	MOVE Z,(Y)			; get system name
	MOVE Y,FSOCKT			; and ICP socket
	CAMN Z,[ASCII/TIP/]		; on a TIP?  (with SUPDUP???)
	 TRNE Y,177774			; just paranoh↓{ make sure a TIP port
	  JRST NOTTIP
	MOVEI Z,"#
	IDPB Z,X
	LSH Y,-16.
	IDIVI Y,8.			; ports are octal
	JUMPE Y,1DIGTP
	ADDI Y,"0 ? IDPB Y,X
1DIGTP:	ADDI Z,"0 ? IDPB Z,X
NOTTIP:	MOVEM X,TERMBP
	PUSHJ P,SETANM			; set our alias name
	PUSHJ P,UNMHST			; map out the host table
	OUTSTR TERSTR
	OUTSTR [ASCIZ/
/]

; Greet the user

	MOVEI X,[ASCIZ/SU A.I. Lab KL-10
/]
	PUSHJ P,SNDMSG
;GETSIZ GETCNS CHKTRM NOTSAI

SUBTTL Paw over user console characteristics

; Get terminal characteristics

	MOVE Y,[440600,,CNSBLK]		; pointer to characteristics block
	MOVEI Z,6
GETSIZ:	PUSHJ P,NETICW
	IDPB Y
	SOJG Z,GETSIZ
	HLRO X,CNSBLK
	MOVNS Z,X			; size of block
	CAILE Z,CNSBLL-1
	 MOVEI Z,CNSBLL-1		; additional args we don't know about
	IMULI Z,6
GETCNS:	PUSHJ P,NETICW
	IDPB Y
	SOJG Z,GETCNS
	CAIN X,CNSBLL-1
	 JRST CHKTRM
	CAIG X,CNSBLL			; more than we wanted?
	 JRST CHKTRM			; too few
	SUBI X,CNSBLL-1			; too many
	IMULI X,6
	PUSHJ P,NETICW			; eat extra bytes
	SOJG X,.-1

; Check terminal out

CHKTRM:	MOVE TCTYP
	CAIE %TNSFW			; software?
	 JRST [	MOVEI X,[ASCIZ/Sorry, TCTYP must be %TNSFW.
/]
		OUTSTR (X)
		PUSHJ P,SNDMSG
		INTMSK [0]
		PUSHJ P,CLOSER
		JRST SUICID]
	MOVE TTYOPT
	TLNE (%TOOVR)
	 SETOM OVRPRP			; remember overprinting!
	TLNN (%TOSAI)			; FCS terminal?
	 JRST NOTSAI
	MOVEI X,1
	IORM X,MODSET			; set DM128 bit
	SETOM 128CHP
NOTSAI:	AND [%TOERS\%TOMVB\%TOMVU\%TOFCI\%TOLID\%TOCID\%TPCBS]
	CAMN [%TOERS\%TOMVB\%TOMVU\%TOFCI\%TOLID\%TOCID\%TPCBS]
	 JRST GETPTY
	MOVEI X,[ASCIZ\Sorry, your console has insufficient display capabilities.
\]
	OUTSTR (X)
	PUSHJ P,SNDMSG
	INTMSK [0]
	PUSHJ P,CLOSER
	JRST SUICID
;GETPTY MAINL MAINL0

SUBTTL Final initialization

; Get a PTY, put its number in A and other places

GETPTY:	PTYGET A
	 JRST [	MOVEI 254		; MAINTM
		PEEK
		PEEK
		SKIPE
		 SKIPA X,[[ASCIZ/System being debugged, users not allowed on.
/]]
		  MOVEI X,[ASCIZ/All network ports in use.
/]
		PUSHJ P,SNDMSG
		INTMSK [0]
		PUSHJ P,CLOSER
		JRST SUICID]
	HRRZM A,TTYLIN			; dumb interrupts
	MOVSI (A)
	IRPS FOO,,LINCHR XONOFF GAGOFF SETVSZ MODSET IMPSET DTMSET
	 IORM FOO
	TERMIN

; Initialize the user's display mode

	MOVEI %TDNOP
	PUSHJ P,NETOCH
	MOVEI %TDCLR
	PUSHJ P,NETOCH
	PUSHJ P,NETSND

; And get the terminal ready

	MOVE TCMXV
	CAILE VSZMAX
	 MOVEI VSZMAX
	MOVEM TCMXV
	HRRM SETVSZ
	MOVE [-NTYSTS,,TYSBLK]
	TTYSET				; turn GAG bit off
	MOVEI B,↑M
	PTWR1W A
	MOVNI LOKTMO
	MOVEM IDLTIM			; initialize lock timeout
	LOCK				; keep response good
	SETZM NODETP			; okay to detach jobs now
	JRST MAINL0

; Main program loop

MAINL:	IWAIT				; wait for an interrupt
MAINL0:	AOSG NTINTP			; net input?
	 JRST NTISER
	AOSG PTINTP			; PTY input?
	 JRST PTISER
	JRST MAINL			; back to sleep for us
;NTISER

SUBTTL Network input interrupt

NTISER:	PUSHJ P,NETICH			; get character from the network
	 JRST MAINL0			; network input buffer empty
	SKIPL IDLTIM
	 LOCK
	MOVNI 1,LOKTMO
	MOVEM 1,IDLTIM			; reset idle time
	AOSG FLSCNT			; flush this character?
	 JRST NTISER
	SKIPE BKYBTS			; if have bucky bits
	 JRST PTYSN0			; forget all this cruft
	SKIPE EATERP			; getting terminal name?
	 JRST [	IDPB TERMBP		; save character
		JUMPN NTISER
		SETZM EATERP		; got it all
		JRST NTISER]
	AOSN PRESCP
	 JRST [	CAIN ↑\			; quoted?
		 JRST PTYSN0
		CAIN ↑P
		 JRST [	MOVNI 2 ? MOVEM FLSCNT
			JRST NTISER]	; flush two characters
		CAIN ↑C			; redisplay screen?
		 JRST [	PUSH P,["P]	; [BREAK]P command fixifies us
			SETZ B,
			PTWR1S A	; send first part of [ESCAPE]
			 JFCL		; will lose soon enough
			MOVEI B,"-	; convert [ESCAPE] to [BREAK]
			JRST PTYSN2]
		TRZN 100		; bucky bits?
		 JRST NTISER		; losing somehow
		LSH 7
		MOVEM BKYBTS
		JRST NTISER]
	AOSN SDCMDP
	 JRST [	CAIN 301		; logout?
		 SETOM NODETP
		CAIN 302		; get terminal name?
		 JRST [	SETOM EATERP
			MOVEI ":
			IDPB TERMBP
			MOVEI <" >
			IDPB TERMBP
			JRST NTISER]
		JRST NTISER]
	CAIN 300			; start of protocol command?
	 JRST [	SETOM SDCMDP
		JRST NTISER]
	CAIN ↑\				; protocol escape command?
	 JRST [	SETOM PRESCP
		JRST NTISER]
;PTYSN0 FNYQOT PTYSN1 PTYSN2 PTYSND

; Send character to the PTY

PTYSN0:	MOVE B,
	IOR B,BKYBTS			; add in bucky bits
	SETZM BKYBTS
	MOVE X,B
	TRZ X,%TXMTA\%TXCTL		; get character without CONTROL and META
	CAIN X,%TXTOP\"β		; beta?
	 JRST @FNYQOT
	CAIE X,%TXTOP\"≡		; equivalence?
	 CAIN X,%TXTOP\"∨		; or?
FNYQOT:	  JRST [PUSH P,B
		SETZ B,			; quote with escape
		PTWR1S A
		 JFCL
		POP P,B
		JRST PTYSN1]
	CAIN X,%TXTOP\"_		; underscore?
	 JRST [	MOVEI X,137
		DPB X,[000700,,B]
		JRST PTYSN1]
	CAIN X,%TXTOP\↑K		; uparrow?
	 JRST [	MOVEI X,"↑
		DPB X,[000700,,B]
		JRST PTYSN1]
	CAIN X,"←			; backarrow?
	 JRST [	MOVEI X,030
		DPB X,[000700,,B]
		JRST PTYSN1]
	CAIN X,↑Z			; [CALL]?
	 JRST [	MOVEI X,↑C		; yes, convert to our [CALL]
		DPB X,[000700,,B]
		JRST PTYSN1]
	CAIN X,%TXTOP\"A		; [ESCAPE]?
	 JRST [	SETZ B,
		JRST PTYSND]
	CAIN X,%TXTOP\"B		; [BREAK]?
	 JRST [	PUSH P,["-]
		SETZ B,
		JRST PTYSN2]
	CAIN X,%TXTOP\"C		; [CLEAR]?
	 JRST [	MOVEI B,↑↑
		JRST PTYSND]
PTYSN1:	TRZ B,%TXTOP			; flush top now
	TRZN B,%TXMTA			; meta set?
	 JRST PTYSND
	PUSH P,B
	MOVEI B,200			; <EDIT>[NULL]
PTYSN2:	PTWR1S A			; send prefix meta command
	 JFCL				; will lose soon enough
	POP P,B
PTYSND:	PTWR1S A			; send character to PTY
	 JRST [	MOVEI %TDBEL		; bell
		PUSHJ 17,NETOCH
		PUSHJ 17,NETSND		; output it
		JRST NTISER]
	JRST NTISER			; try for more user characters
;PTISER PTISR1 CHKCYP CHKDMC DMSND DMSND0 MRKNBL ISPCH NOTPCH

SUBTTL PTY input interrupt

PTISER:	MOVE B,[441140,,PTIBUF]
	PTRDS A				; read buffer from PTY
	ILDB B
	JUMPE [	PUSHJ P,NETSND		; buffer empty, force output out
		JRST MAINL0]
	SKIPA D,
PTISR1:	 ILDB D,B
	JUMPE D,PTISER
	MOVNI LOKTMO
	MOVEM IDLTIM			; reset idle time
	ANDI D,377			; flush funny 400 bit
	AOSN LFFLSP			; flush a line feed?
	 CAIE D,↑J
	  CAIA
	   JRST PTISR1
	AOSN QUOTEP			; quote frob?
	 JRST DMSND
	AOSN GETCXP			; set X position?
	 CAIG D,↑←			; yes, abort?
	  JRST CHKCYP
	XORI D,140
	CAMLE D,TCMXH			; beyond screen limit?
	 SETZ D,
	MOVEM D,HPOS
	SETOM GETCYP
	JRST PTISR1

CHKCYP:	AOSN GETCYP			; set Y position?
	 CAIG D,↑←			; yes, abort?
	  JRST CHKDMC
	XORI D,140
	CAML D,TCMXV			; beyond screen limit?
	 SETZ D,
	MOVEM D,VPOS
	JRST SETCPS			; finally set position

CHKDMC:	CAIG D,<" >			; DM command?
	 XCT DMCTAB(D)
DMSND:	CAIN D,013			; integral sign?
	 JRST [	MOVEI D,177
		JRST DMSND0]
	CAIN D,"_			; underscore?
	 JRST [	MOVEI D,137
		JRST DMSND0]
	SKIPN 128CHP
	 JRST DMSND0
	CAIN D,"↑			; uparrow?
	 JRST [	MOVEI D,013
		JRST DMSND0]
	CAIN D,"←			; backarrow?
	 JRST [	MOVEI D,030
		JRST DMSND0]
	CAIN D,177			; circumflex?
	 JRST [	MOVEI D,136
		JRST DMSND0]
DMSND0:	CAIL D,200			; a %TD code?
	 JRST NOTPCH
	SKIPN OVRPRP
	 JRST ISPCH
	PUSHJ P,GETSMD
	TDNN X,(Y)
	 JRST MRKNBL			; position already blank
	MOVEI %TDDLF			; delete character at this position
	PUSHJ P,NETOCH
MRKNBL:	IORM X,(Y)			; mark position as non-blank
ISPCH:	AOS HPOS			; no, account for character
NOTPCH:	MOVE D
	PUSHJ P,NETOCH
	JRST PTISR1
;SCLEAR CANCEL CLEOL SETCPS INSLIN IDCMND SPACE FORSPC

; Datamedia conversion subroutines

SCLEAR:	MOVEI %TDCLR			; clear screen
	PUSHJ P,NETOCH
	SETZM HPOS			; home up
	SETZM VPOS
	SKIPN OVRPRP
	 JRST CANCEL
	SETZM SCRMST			; clear screen bit mask
	MOVE [SCRMST,,SCRMST+1]
	BLT SCRMST+3*VSZMAX-1
	CAIA				; roll isn't cancelled by this
CANCEL:	 SETZM ROLLP
	SETZM INDLMP
;	MOVEI %TDRST
;	PUSHJ P,NETOCH
	JRST PTISR1

CLEOL:	MOVEI %TDEOL
	PUSHJ P,NETOCH
	SKIPN OVRPRP
	 JRST PTISR1
	PUSHJ P,GETSMD
	ANDCAM X,(Y)			; flag current position as blank
	SUBI X,1
	ANDCAM X,(Y)			; flag rest of word as blank
	CAIE Z,2
	 SETZM 1(Y)			; 0 or 1 → flag next word as blank
	JUMPN Z,PTISR1
	SETZM 2(Y)			; 0 → flag word after that as blank
	JRST PTISR1

SETCPS:	MOVEI %TDMV0			; set cursor position
	PUSHJ P,NETOCH
	MOVE VPOS
	CAML TCMXV			; beyond screen limit?
	 SETZB VPOS			; paranoia for dumb ITS SUPDUP
	PUSHJ P,NETOCH
	MOVE HPOS
	CAMLE TCMXH
	 SETZM HPOS
	PUSHJ P,NETOCH
	JRST PTISR1

INSLIN:	MOVEI %TDILP
	SKIPN OVRPRP
	 JRST IDCMND
	MOVEI X,VSZMAX-1
	SUB X,VPOS			; # of lines to move
	IMULI X,3
	ADDI X,377777			; # of lines-1 w/ sign bit
	HRL X,X
	HRRI X,SCRMST+3*<VSZMAX-1>-1	; source address
	POP X,3(X)			; reverse BLT
	JUMPL X,.-1
IDCMND:	PUSHJ P,NETOCH			; insert/delete mode command
	MOVEI 1
	PUSHJ P,NETOCH
	JRST PTISR1

SPACE:	MOVEI %TDDLF
	PUSHJ P,NETOCH
	SKIPN OVRPRP
	 JRST FORSPC
	PUSHJ P,GETSMD
	ANDCAM X,(Y)			; flag position as blank
FORSPC:	MOVEI %TDFS			; forespace
	PUSHJ P,NETOCH
	AOS HPOS
	JRST PTISR1
;DMCTAB

SUBTTL Datamedia command table

DMCTAB:	JRST PTISR1			; ↑@ no-op
	JRST PTISR1			; ↑A no-op
	JRST [	SETZM HPOS		; ↑B home up
		SETZM VPOS
		JRST SETCPS]
	JRST PTISR1			; ↑C no-op
	JRST PTISR1			; ↑D no-op
	JRST PTISR1			; ↑E no-op
	JRST PTISR1			; ↑F no-op
	MOVEI D,%TDBEL			; ↑G bell
	JRST [	SKIPE INDLMP		; ↑H backspace/delete character
		 JRST [	MOVEI %TDDCP
			SKIPN OVRPRP
			 JRST IDCMND
			PUSHJ P,GETSMD
			MOVE D,(Y)
			LSH X,1
			SUBI X,1	; mask for bits being hacked
			ANDCAM X,(Y)
			LSH D,1		; shift characters over
			AND D,X
			IORM D,(Y)
			CAIN Z,2
			 JRST IDCMND
			MOVEI C,1	; bit to bring in previous words if needed
			MOVE D,1(Y)
			LSH D,1		; shift characters over
			TLZE D,(1←32.)
			 IORM C,(Y)	; bring in overflow to next word
			MOVEM D,1(Y)
			JUMPN Z,IDCMND	; if last word flush
			MOVE D,2(Y)
			LSH D,1
			TLZE D,(1←32.)
			 IORM C,1(Y)
			MOVEM D,2(Y)
			JRST IDCMND]
		SOSGE HPOS
		 SETZM HPOS
		JRST SETCPS]
	JRST [	MOVE HPOS		; ↑I tab
		TRZ 7
		ADDI 8.
		MOVEM HPOS
		JRST SETCPS]
	JRST [	SKIPE INDLMP		; ↑J line feed/insert line
		 JRST INSLIN
		AOS VPOS
		JRST SETCPS]
	JRST PTISR1			; ↑K tab clear (no-op)
	JRST [	SETOM GETCXP		; ↑L cursor position
		JRST PTISR1]
	JRST [	AOS X,VPOS		; ↑M terpri
		SETZM HPOS
		SETOM LFFLSP
		SKIPN ROLLP		; scrolling?
		 JRST [	CAML X,TCMXV	; not scrolling; gone off bottom?
			 SETZM VPOS	; yes, wrap around to top of screen
			JRST SETCPS]	; use %TDMV0 to move cursor
		MOVEI %TDCRL		; scrolling, use %TDCRL instead
		PUSHJ P,NETOCH
		CAMGE X,TCMXV
		 JRST PTISR1
		MOVE TCMXV		; somehow we scrolled
		SOS
		MOVEM VPOS
		MOVE [SCRMST+3,,SCRMST]
		BLT SCRMST+3*VSZMAX-1
		JRST PTISR1]
;	MOVEI D,%TDBOW			; ↑N blink on (set complement mode)
	JRST PTISR1			; ↑N blink on (no op for now)
	JRST PTISR1			; ↑O bold on (no-op)
	JRST [	SETOM INDLMP		; ↑P enter I/D mode
		JRST PTISR1]
; More DM command frobs

	JRST PTISR1			; ↑Q transmit page to computer (no-op)
	JRST PTISR1			; ↑R transmit page to printer (no-op)
	JRST PTISR1			; ↑S transmit line to computer (no-op)
	JRST PTISR1			; ↑T no-op
	JRST PTISR1			; ↑U no-op
	JRST PTISR1			; ↑V no-op
	JRST CLEOL			; ↑W erase to end of line
	JRST CANCEL			; ↑X cancel bold, I/D, roll
	JRST PTISR1			; ↑Y set tab (no-op)
	JRST [	SKIPE INDLMP		; ↑Z line starve/delete row
		 JRST [	MOVEI %TDDLP
			SKIPN OVRPRP
			 JRST IDCMND
			MOVE X,VPOS
			LSH X,1
			ADD X,VPOS
			ADDI X,SCRMST
			HRLI X,3(X)
			BLT X,SCRMST+3*VSZMAX-1
			JRST IDCMND]
		SOSGE VPOS
		 SETZM VPOS
		JRST SETCPS]
	JRST [	SETOM QUOTEP		; ↑[ quote FCS character
		JRST PTISR1]
	JRST [	SKIPN INDLMP		; ↑\ forespace/insert character
		 JRST FORSPC
		MOVEI %TDICP
		SKIPN OVRPRP
		 JRST IDCMND
		PUSHJ P,GETSMD
		MOVE D,(Y)
		LSH X,1
		SUBI X,1		; fill in mask to the right
		ANDCAM X,(Y)
		AND D,X
		LSHC D,-1
		IORM D,(Y)
		CAIN Z,2
		 JRST IDCMND
		MOVE D,1(Y)
		SKIPGE C
		 TLO D,(1←31.)		; bring in bit from previous word
		LSHC D,-1
		MOVEM D,1(Y)
		JUMPN Z,IDCMND
		MOVE D,2(Y)
		SKIPGE C
		 TLO D,(1←31.)
		LSH D,-1
		TRZ D,100000		; flush overflow bit
		MOVEM D,2(Y)
		JRST IDCMND]
	JRST [	SETOM ROLLP		; ↑] roll on
		JRST PTISR1]
	JRST SCLEAR			; ↑↑ master clear
	JRST SCLEAR			; ↑← erase screen
	JRST SPACE			; sp delete character and forespace
IFN .-DMCTAB-1-" ,.ERR DMCTAB loses!
;GETSMD BITTAB SNDMSG MSGLUP INTDIE SUICID DIEDIE ...LIT

SUBTTL Subroutines

; Get screen mask data in Y, Z, X

GETSMD:	MOVE Y,VPOS
	LSH Y,1
	ADD Y,VPOS
	MOVE Z,HPOS
	LSH Z,-5			; Z ← word index in line (for cleol)
	ADDI Y,SCRMST(Z)		; Y ← addr of screen mask word
	MOVE X,HPOS
	ANDI X,37
	MOVE X,BITTAB(X)		; X ← mask for this byte
	POPJ P,

; Bit table

BITTAB:	REPEAT 32.,1←<31.-.RPCNT>	; bit table

; Send a message, b.p. in X

SNDMSG:	TLOA X,440700			; set up b.p.
MSGLUP:	 PUSHJ P,NETOCH
	ILDB X
	JUMPN MSGLUP			; continue until a null hit
	JRST NETSND

; Here to suicide on network errors or idle timeout

INTDIE:	INTMSK [0]			; no more interrupts
	DEBREAK				; out of interrupt level
SUICID:	OUTSTR [ASCIZ/Connection closed.
/]
	SKIPE NODETP
	 JRST DIEDIE			; logout the guy
	MOVE TTYLIN
	TTYJOB
	JUMPE DIEDIE
	MOVE A,TTYLIN
	MOVEI B,7
	PTJOBX A			; clear PTY's input buffer
	MOVEI 2
	MOVEI B,10			; DETACH
	PTJOBX A
	 JRST [	SLEEP ? JRST .-1]
	SLEEP
	PTRD1S A			; slurp up stuff in buffer
	 CAIA
	  JRST .-2
DIEDIE:	RESET ? EXIT

...LIT:	CONSTANTS

; Wonderful network routines

SVRRTS==-1				; include server routines
ERRTNS==-1				; include error routines
ERRHAN==-1				; include automagic error handling
ERRINS==<JRST SUICID>			; error instruction
HSTTAB==-1				; include host table magic
HSTSIX==-1				; and alias name kludge

.INSRT NETWRK[NET,MRC]

END SUPSER